《Android开源库》 Realm For Android~ Realm(译文)

Realm

Realm(s) 是我们对数据库的称谓:它包含多个不同的对象,并对应磁盘中的一个文件。在使用之前,需要对 Realm 库进行初始化操作:

1
Realm.init(context);

你需要提供一个安卓的 Context 对象来对 Realm 进行初始化。初始化操作只要进行一次。继承 Application 并在重载的 onCreate() 方法中进行初始化是个不错的主意。

1
2
3
4
5
6
7
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Realm.init(this);
}
}

请别忘了修改 AndroidManifest.xml:

1
2
3
4
<application
android:name=".MyApplication"
...
/>

配置Realm

RealmConfiguration 用来配置要被创建的 Realm 的各种特性。最简配置如下所示:

1
RealmConfiguration config = new RealmConfiguration.Builder().build();

如上配置的 Realm 会被存储在 Context.getFilesDir() 并且命名为 default.realm。

一个典型的配置如下所示:

1
2
3
4
5
6
7
8
9
10
11
// The RealmConfiguration is created using the builder pattern.
// The Realm file will be located in Context.getFilesDir() with name "myrealm.realm"
RealmConfiguration config = new RealmConfiguration.Builder()
.name("myrealm.realm")
.encryptionKey(getKey())
.schemaVersion(42)
.modules(new MySchemaModule())
.migration(new MyMigration())
.build();
// Use the config
Realm realm = Realm.getInstance(config);

你还可以有多个RealmConfiguration。如此,你便可以控制Realm的版本、结构(schema)和路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
RealmConfiguration myConfig = new RealmConfiguration.Builder()
.name("myrealm.realm")
.schemaVersion(2)
.modules(new MyCustomSchema())
.build();

RealmConfiguration otherConfig = new RealmConfiguration.Builder()
.name("otherrealm.realm")
.schemaVersion(5)
.modules(new MyOtherSchema())
.build();

Realm myRealm = Realm.getInstance(myConfig);
Realm otherRealm = Realm.getInstance(otherConfig);

你可以使用 Realm.getPath() 来获取 Realm 文件的绝对路径。

很重要的一点是 Realm 实例是线程单例化的,也就是说多次在同一线程调用静态构建器会返回同一 Realm 实例。

默认 RealmConfiguration

RealmConfiguration可以保存为默认配置。通过在自定义的Application设置默认的Realm配置,可以使你在代码中的其他地方更加方便地创建针对该默认配置的Realm。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// The Realm file will be located in Context.getFilesDir() with name "default.realm"
Realm.init(this);
RealmConfiguration config = new RealmConfiguration.Builder().build();
Realm.setDefaultConfiguration(config);
}
}

public class MyActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Realm realm = Realm.getDefaultInstance();
try {
// ... Do something ...
} finally {
realm.close();
}
}
}

In-Memory Realm

定义一个非持久化的、存在于内存中的 Realm 实例:

1
2
3
4
RealmConfiguration myConfig = new RealmConfiguration.Builder()
.name("myrealm.realm")
.inMemory()
.build();

这样就可以创建一个存在于“内存中的” Realm。“内存中的”Realm 在内存紧张的情况下仍有可能使用到磁盘存储,但是这些磁盘空间都会在Realm实例完全关闭的时候被释放。

请注意使用同样的名称同时创建“内存中的”Realm 和常规的(持久化)Realm 是不允许的。

当某个“内存中的”Realm 的所有实例引用都被释放,该 Realm 下的数据也同时会被清除。建议在你的应用生命周期中保持对“内存中的” Realm 实例的引用以避免非期望的数据丢失。

Dynamic Realm

对于普通的 Realm 来说,数据模型被定义成了 RealmObject 的子类。这样做保证了类型安全,但有时候某些数据模型在编译期是无法获得的。例如在处理数据迁移(migration)或CSV文件的时候。

DynamicRealm 是普通 Realm 的一个变种。它可以在没有 RealmObject 子类的情况下操作 Realm 数据。其对数据的访问是基于字符串而非 RealmObject 的定义。

创建 Dynamic Realm 使用与创建普通 Realm 相同的RealmConfiguration,但是它的创建过程会忽略对 schema、migration以及 schema 版本的检查。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
RealmConfiguration realmConfig = new RealmConfiguration.Builder().build();
DynamicRealm realm = DynamicRealm.getInstance(realmConfig);

// In a DynamicRealm all objects are DynamicRealmObjects
DynamicRealmObject person = realm.createObject("Person");

// All fields are accessed using strings
String name = person.getString("name");
int age = person.getInt("age");

// An underlying schema still exists, so accessing a field that does not exist
// will throw an exception
person.getString("I don't exist");

// Queries still work normally
RealmResults<DynamicRealmObject> persons = realm.where("Person")
.equalTo("name", "John")
.findAll();

DynamicRealm 以类型安全和性能为代价,换来了更多的灵活性。请在你确实需要这些灵活性的情况下使用。

关闭Realm实例

Realm 实现了 Closeable 接口以便与释放 native 内存和文件描述符,请务必在使用完毕后关闭 Realm 实例。

Realm 实例是基于引用计数的, 也就是说假设你在同一个线程中调用了 getInstance() 两次,你需要同样调用 close() 两次以关闭该实例。举例来说,如果你需要实现 Runnable,简单地在函数开始的时候调用 getInstance(),在函数结束的时候调用 close() 即可!

对于UI线程,你可以选择在 onDestroy() 方法内调用 realm.close()。

如果你想使用除 UI 线程外的 Looper 线程,可以参考以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class MyThread extends Thread {

private Realm realm;

public void run() {
Looper.prepare();
try {
realm = Realm.getDefaultInstance();
//... Setup the handlers using the Realm instance ...
Lopper.loop();
} finally {
if (realm != null) {
realm.close();
}
}
}
}

对于 AsyncTask,这里有个不错的例子可以参考:

1
2
3
4
5
6
7
8
9
10
protected Void doInBackground(Void... params) {
Realm realm = Realm.getDefaultInstance();
try {
// ... Use the Realm instance ...
} finally {
realm.close();
}

return null;
}

如果你想使用 Thread 和 Runnable 进行一些短期任务,参考如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/ Run a non-Looper thread with a Realm instance.
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Realm realm = null;
try {
realm = Realm.getDefaultInstance();
// ... Use the Realm instance ...
} finally {
if (realm != null) {
realm.close();
}
}
}
});

thread.start();

如果你很幸运地工作在 minSdkVersion >= 19 且 Java >= 7 之下,可以使用try-with-resources:

1
2
3
try (Realm realm = Realm.getDefaultInstance()) {
// No need to close the Realm instance manually
}

自动刷新

如果 Realm 实例存在于一个带有 Looper 的线程,那么这个 Realm 实例即具有自动更新的功能。这意味这如果发生了 Realm 数据库的变化,那么该 Realm 实例会在下一个事件循环(event loop)中自动更新。这个便捷的功能使你不必花费太多的精力就能保证的UI与数据的实时同步。

如果 Realm 的实例所在线程没有绑定 Looper,那么该实例不会被更新直到你手动调用 waitForChange() 方法。请注意,不更新 Realm 以保持对旧数据的引用会造成而外的磁盘和内存开销。这也是为什么要在线程结束时调用 close() 关闭 Realm 实例的一个重要原因。

如果你想确定当前 Realm 实例是否有自动更新功能,可以通过调用 isAutoRefresh() 方法查询。

查找 Realm 数据库文件

如果你想知道你应用的 Realm 文件的具体路径,请参见这个 StackOverflow上的答案。

原文链接

https://realm.io/docs/java/latest/#realms

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×